package com.ibeetl.admin.core.web;

import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.beetl.core.Configuration;
import org.beetl.core.GroupTemplate;
import org.beetl.core.Template;
import org.beetl.core.resource.ClasspathResourceLoader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.ibeetl.admin.core.gen.AutoGen;
import com.ibeetl.admin.core.gen.HtmlGen;
import com.ibeetl.admin.core.gen.JSGen;
import com.ibeetl.admin.core.gen.JavaCodeGen;
import com.ibeetl.admin.core.gen.MavenProjectTarget;
import com.ibeetl.admin.core.gen.MdGen;
import com.ibeetl.admin.core.gen.WebTarget;
import com.ibeetl.admin.core.gen.model.Attribute;
import com.ibeetl.admin.core.gen.model.Entity;
import com.ibeetl.admin.core.service.CoreCodeGenService;
import com.ibeetl.admin.core.util.PlatformException;

@Controller
public class CoreCodeGenController {
    private final Log log = LogFactory.getLog(this.getClass());
    private static final String MODEL = "/core/codeGen";

    @Autowired
    CoreCodeGenService codeGenService;

    @GetMapping(MODEL + "/index.do")
    public ModelAndView index() {
        ModelAndView view = new ModelAndView("/core/codeGen/index.html");
        return view;

    }
    
    @PostMapping(MODEL + "/refresh.json")
    @ResponseBody
    public JsonResult<Boolean> refresh() {
        codeGenService.refresh();
        return JsonResult.success();
    }


    @GetMapping(MODEL + "/tableDetail.do")
    public ModelAndView tableDetail(String table) {
        ModelAndView view = new ModelAndView("/core/codeGen/edit.html");
        Entity entity = codeGenService.getEntityInfo(table);
        view.addObject("entity", entity);
        return view;

    }
    
    @GetMapping(MODEL + "/project.do")
    public ModelAndView project() {
        ModelAndView view = new ModelAndView("/core/codeGen/project.html");
        File file = new  File(MavenProjectTarget.detectRootPath());
        String root = file.getParent();
        //设置生成项目为当前运行项目的上一级项目
        view.addObject("path",root+File.separator+"sample");
        view.addObject("basePackage","com.corp.xxx");
        return view;
      
    }
    
    @PostMapping(MODEL + "/projectGen.json")
    @ResponseBody
    public JsonResult project(String path,String basePackage,String includeConsole) throws IOException {
        //includeConsole 当前版本忽略，总是添加一个系统管理功能，可以在pom中移除console
        
        //生成maven项目结构
        File maven = new  File(path);
        maven.mkdirs();
        File src = new File(maven,"src");
        src.mkdirs();
        File main = new File(src,"main");
        main.mkdir();
        File test = new File(src,"test");
        test.mkdir();
        File javsSource = new File(main,"java"); 
        javsSource.mkdir();
        File resource = new File(main,"resources"); 
        resource.mkdir();
        File sql = new File(resource,"sql"); 
        sql.mkdir();
        File staticFile = new File(resource,"static"); 
        staticFile.mkdir();
        File templatesFile = new File(resource,"templates"); 
        templatesFile.mkdir();
        
        String codePath = basePackage.replace(".", "/");
        File codeFile = new File(javsSource,codePath);
        codeFile.mkdirs();
        Configuration conf = Configuration.defaultConfiguration();
        String tempalteRoot = "codeTemplate/maven/";
        ClasspathResourceLoader loader = new ClasspathResourceLoader(Thread.currentThread().getContextClassLoader(),tempalteRoot);
        GroupTemplate gt = new GroupTemplate(loader,conf);
        FileWriter fw = null;
        
        //先生成入口程序
        Template mainJavaTempalte = gt.getTemplate("/main.java");
        mainJavaTempalte.binding("basePackage", basePackage);
        fw = new FileWriter(new File(codeFile,"MainApplication.java"));
        mainJavaTempalte.renderTo(fw);
       
        
        //生成pom文件
        Template pomTemplate = gt.getTemplate("/pomTemplate.xml");
        int index = basePackage.lastIndexOf(".");
        String projectGrop = basePackage.substring(0, index);
        String projectName = basePackage.substring(index+1);
        pomTemplate.binding("group", projectGrop);
        pomTemplate.binding("project", projectName);
        fw = new FileWriter(new File(maven,"pom.xml"));
        pomTemplate.renderTo(fw);
        
        //复制当前项目的配置文件
        File config = copy(resource,"application.properties");
        copy(resource,"beetl.properties");
        copy(resource,"btsql-ext.properties");
        copy(resource,"banner.txt");
   
        return JsonResult.success();
    }
    
    
    private File copy(File root,String fileName) throws IOException {
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        InputStream input = loader.getResourceAsStream(fileName);
        if(input==null) {
            log.info("copy "+fileName+" error,不存在"); 
            return null;
        }
        
        File target = new File(root,fileName);
        FileOutputStream output = new FileOutputStream(target);
        try {
                
            byte[] buf = new byte[1024];        
            int bytesRead;        
            while ((bytesRead = input.read(buf)) > 0) {
                output.write(buf, 0, bytesRead);
            }
         } finally {
             input.close();
             output.close();
         }
        return target;
    }
    
    
    

    @PostMapping(MODEL + "/table.json")
    @ResponseBody
    public JsonResult<List<Entity>> getTable() {
        List<Entity> list = codeGenService.getAllEntityInfo();
        return JsonResult.success(list);
    }

    @PostMapping(MODEL + "/tableDetail.json")
    @ResponseBody
    public JsonResult<Entity> getInfo(String table) {
        Entity entity = codeGenService.getEntityInfo(table);
        if (entity == null) {
            JsonResult.failMessage("表不存在");
        }
        return JsonResult.success(entity);

    }

    @PostMapping(MODEL + "/gen.json")
    @ResponseBody
    public JsonResult gen(EntityInfo data,String path) {
        Entity  entity = getEntitiyInfo(data);
        String urlBase = data.getUrlBase();
        String basePackage = data.getBasePackage();
        
        MavenProjectTarget target = new MavenProjectTarget(entity, basePackage);
        //生成到path目录下，按照maven工程解构生成
        File file = new File(path);
        if(!file.exists()) {
            throw new PlatformException("路径不存在 "+path);
        }
        target.setTargetPath(path);
        target.setUrlBase(urlBase);

        JSGen jsGen = new JSGen();
        jsGen.make(target, entity);

        HtmlGen htmlGen = new HtmlGen();
        htmlGen.make(target, entity);
        String  preffix =  urlBase.replace('/', '.');
        String basicFunctionCode = preffix+"."+entity.getCode();
        JavaCodeGen javaGen = new JavaCodeGen(basePackage, entity,basicFunctionCode);
        javaGen.make(target, entity);

        MdGen mdGen = new MdGen(basicFunctionCode);
        mdGen.make(target, entity);
        if(entity.isAutoAddMenu()||entity.isAutoAddFunction()) {
            //自动增加功能点
            long  functionId = this.codeGenService.insertFunction(entity, urlBase);
            if(entity.isAutoAddMenu()) {
                this.codeGenService.insertMenu(functionId, entity, urlBase);
            }
        }
        
        
        
        return JsonResult.success();

    }
    
    @PostMapping(MODEL + "/getPath.json")
    @ResponseBody
    public JsonResult<String> getPath() {
        String path = MavenProjectTarget.detectRootPath();
        return JsonResult.success(path);
    }

    @PostMapping(MODEL + "/html.json")
    @ResponseBody
    public JsonResult<Map<String, String>> html(EntityInfo data) {
        
        Entity entity = getEntitiyInfo(data);
        String urlBase = data.getUrlBase();
        String basePackage = data.getBasePackage();
        WebTarget webTarget = new WebTarget(entity, basePackage);
        webTarget.setUrlBase(urlBase);
        HtmlGen htmlGen = new HtmlGen();
        htmlGen.make(webTarget, entity);
        Map<String, String> content = new HashMap<String, String>();
        for (Entry<Object, String> entry : webTarget.map.entrySet()) {
            AutoGen gen = (AutoGen) entry.getKey();
            String code = entry.getValue();
            content.put(gen.getName(), code);
        }
        return JsonResult.success(content);

    }
    
    @PostMapping(MODEL + "/js.json")
    @ResponseBody
    public JsonResult<Map<String, String>> js(EntityInfo data) {
        
        Entity entity = getEntitiyInfo(data);
        String urlBase = data.getUrlBase();
        String basePackage = data.getBasePackage();
        WebTarget webTarget = new WebTarget(entity, basePackage);
        webTarget.setUrlBase(urlBase);
        JSGen jsGen = new JSGen();
        jsGen.make(webTarget, entity);
        Map<String, String> content = new HashMap<String, String>();
        for (Entry<Object, String> entry : webTarget.map.entrySet()) {
            AutoGen gen = (AutoGen) entry.getKey();
            String code = entry.getValue();
            content.put(gen.getName(), code);
        }
        return JsonResult.success(content);

    }
    
    @PostMapping(MODEL + "/java.json")
    @ResponseBody
    public JsonResult<Map<String, String>> javaCode(EntityInfo data) {
        
        Entity entity = getEntitiyInfo(data);
        String urlBase = data.getUrlBase();
        String basePackage = data.getBasePackage();
        WebTarget webTarget = new WebTarget(entity, basePackage);
        webTarget.setUrlBase(urlBase);
        
        String  preffix =  urlBase.replace('/', '.');
        String basicFunctionCode = preffix+"."+entity.getCode();
        JavaCodeGen javaGen = new JavaCodeGen(basePackage,entity,basicFunctionCode);
        javaGen.make(webTarget, entity);
        Map<String, String> content = new HashMap<String, String>();
        for (Entry<Object, String> entry : webTarget.map.entrySet()) {
            AutoGen gen = (AutoGen) entry.getKey();
            String code = entry.getValue();
            content.put(gen.getName(), code);
        }
        
        
        return JsonResult.success(content);

    }
    
    @PostMapping(MODEL + "/sql.json")
    @ResponseBody
    public JsonResult<Map<String, String>> sql(EntityInfo data) {
        
        Entity entity = getEntitiyInfo(data);
        String urlBase = data.getUrlBase();
        String basePackage = data.getBasePackage();
        WebTarget webTarget = new WebTarget(entity, basePackage);
        webTarget.setUrlBase(urlBase);
        String  preffix =  urlBase.replace('/', '.');
        String basicFunctionCode = preffix+"."+entity.getCode();
        MdGen javaGen = new MdGen(basicFunctionCode);
        
          
        javaGen.make(webTarget, entity);
        Map<String, String> content = new HashMap<String, String>();
        for (Entry<Object, String> entry : webTarget.map.entrySet()) {
            AutoGen gen = (AutoGen) entry.getKey();
            String code = entry.getValue();
            content.put(gen.getName(), code);
        }
        return JsonResult.success(content);

    }
    
    private Entity getEntitiyInfo(EntityInfo data) {
        Entity info = data.getEntity();
        String urlBase = data.getUrlBase();
        String basePackage = data.getBasePackage();
        Entity entity = codeGenService.getEntityInfo(info.getTableName());
        entity.setCode(info.getCode());
        entity.setDisplayName(info.getDisplayName());
        entity.setSystem(info.getSystem());
        entity.setAttachment(data.entity.isAttachment());
        entity.setIncludeExcel(data.entity.isIncludeExcel());
        entity.setAutoAddFunction(info.isAutoAddFunction());
        entity.setAutoAddMenu(info.isAutoAddFunction());
        for (int i = 0; i < entity.getList().size(); i++) {
            Attribute attr = entity.getList().get(i);
            attr.setDisplayName(info.getList().get(i).getDisplayName());
            attr.setShowInQuery(info.getList().get(i).isShowInQuery());
            attr.setDictType(info.getList().get(i).getDictType());
            attr.setVerifyList(info.getList().get(i).getVerifyList());
            if(attr.getName().equals(data.getNameAttr())) {
                entity.setNameAttribute(attr);
            }
        }
        
        if (StringUtils.isEmpty(entity.getCode()) || StringUtils.isEmpty(entity.getSystem())) {
            throw new PlatformException("code,system不能为空");
        }
        
        
        return entity;
    }
    

    

    @GetMapping(MODEL + "/{table}/test.json")
    @ResponseBody
    public void test(@PathVariable String table) {
        String urlBase = "cms";
        Entity entity = new Entity();
        entity.setCode("blog");
        entity.setName("CmsBlog");
        entity.setDisplayName("博客");
        entity.setTableName("CMS_BLOG");
        entity.setSystem("console");
        

        Attribute idAttr = new Attribute();
        idAttr.setColName("id");
        idAttr.setJavaType("Long");
        idAttr.setName("id");
        idAttr.setDisplayName("编号");
        idAttr.setId(true);
        entity.setIdAttribute(idAttr);

        Attribute nameAttr = new Attribute();
        nameAttr.setColName("title");
        nameAttr.setJavaType("String");
        nameAttr.setName("title");
        nameAttr.setDisplayName("标题");
        nameAttr.setShowInQuery(true);

        Attribute contentAttr = new Attribute();
        contentAttr.setColName("content");
        contentAttr.setJavaType("String");
        contentAttr.setName("content");
        contentAttr.setDisplayName("内容");
        contentAttr.setShowInQuery(true);

        Attribute createTimeAttr = new Attribute();
        createTimeAttr.setColName("create_time");
        createTimeAttr.setJavaType("Date");
        createTimeAttr.setName("createTime");
        createTimeAttr.setDisplayName("创建日期");
        createTimeAttr.setShowInQuery(true);

        Attribute createUserIdAttr = new Attribute();
        createUserIdAttr.setColName("create_user_id");
        createUserIdAttr.setJavaType("Long");
        createUserIdAttr.setName("createUserId");
        createUserIdAttr.setDisplayName("创建人");
        createUserIdAttr.setShowInQuery(true);

        Attribute typeAttr = new Attribute();
        typeAttr.setColName("type");
        typeAttr.setJavaType("String");
        typeAttr.setName("type");
        typeAttr.setDisplayName("博客类型");
        typeAttr.setShowInQuery(true);

        entity.getList().add(idAttr);
        entity.getList().add(nameAttr);
        entity.getList().add(contentAttr);
        entity.getList().add(createTimeAttr);
        entity.getList().add(createUserIdAttr);
        entity.getList().add(typeAttr);

        entity.setNameAttribute(nameAttr);
        entity.setComment("这是一个测试模型");
        // ConsoleTarget target = new ConsoleTarget();

        String basePackage = "com.ibeetl.admin.console";
        MavenProjectTarget target = new MavenProjectTarget(entity, basePackage);
        target.setUrlBase("admin");

        JSGen jsGen = new JSGen();
        jsGen.make(target, entity);

        HtmlGen htmlGen = new HtmlGen();
        htmlGen.make(target, entity);
        String  preffix =  urlBase.replace('/', '.');
        String basicFunctionCode = preffix+"."+entity.getCode();
        JavaCodeGen javaGen = new JavaCodeGen(basePackage, entity,basicFunctionCode);
        javaGen.make(target, entity);

        MdGen mdGen = new MdGen(basicFunctionCode);
        mdGen.make(target, entity);

    }

}

class EntityInfo {
    Entity entity;
    String urlBase;
    String basePackage;
    String nameAttr;


    public Entity getEntity() {
        return entity;
    }

    public void setEntity(Entity entity) {
        this.entity = entity;
    }

    public String getUrlBase() {
        return urlBase;
    }

    public void setUrlBase(String urlBase) {
        this.urlBase = urlBase;
    }

    public String getBasePackage() {
        return basePackage;
    }

    public void setBasePackage(String basePackage) {
        this.basePackage = basePackage;
    }

    public String getNameAttr() {
        return nameAttr;
    }

    public void setNameAttr(String nameAttr) {
        this.nameAttr = nameAttr;
    }

   

}
